Seminário sobre C++ - Grupo 2
Grupo 2 - 2/2012 - C++: *Felipe Rodopoulos: 10/0100601 *Filipe Caldas: 10/0101356 *Heitor Henrique: 10/0104011 *Paulo Afonso: 10/0118526 *Wallace Bruno: 10/0127380 Introdução A linguagem de programação C++ fornece um modelo de memória e computação muito próximo ao dos computadores. Além disso, como linguagem de orientação a objetos, oferece também mecanismos poderosos e flexíveis de abstração. Ou seja, a linguagem suporta estilos de programação que se apoiam na manipulação quase direta dos recursos de hardware (desempenho alto) e estilos de programação de alto nível que se apoiam em tipos definidos pelo usuário para prover um modelo de dados e computação que se assemelha a visão humana da tarefa que está sendo executada pelo computador. Design e Evolução do C++ C++ foi projetada e implementada por Bjarne Stroustrup no AT&T Bell Laboratories para combinar as vantagens da organização e design do Simula com a facilidade de programação de sistemas do C. Segue algumas modificações importantes do C++ por ano: *1980 - Criada versão incial do C++ chamada “C with Classes”. Tinha suporte para técnicas tradicionais de programação de sistemas e abstração de dados. *1983 - Adicionadas facilidades básicas para POO *1985 - Linguagem foi disponibilizada comercialmente *Entre 87 e 89 - Facilidades para programação genérica *1998 - Padronização internacional ISO 1998 (como a linguagem foi amplamente difundida, surgiram implementações de desenvolvimento independente) O C++ foi projetado para atender a alguns objetivos, dentre os quai destaca-se: *Ser melhor que o C (daí o nome da linguagem C++, seria o próximo C ou C incrementado) *Suportar abstração de dados *Suportar programação orientada a objetos *Suportar programação genérica Além disso foi projetado para ser compatível com o C, exceto quando essa compatibilidade entra em conflito com a forte checagem de tipo do C++. A não ser por pequenos detalhes, C é um subconjunto do C++. 'O Modelo de programação do C' Uma propriedade fundamental dos computadores de uso geral se manteve notavelmente constante: a memória é uma sequência de palavras ou bytes, indexada por inteiros chamados endereços. Além disso, todas máquinas populares têm alguns recursos importantes (como por exemplo input-output) que não se encaixam bem no modelo convencional orientado a byte ou palavras de memória ou computação. Esses recursos podem exigir instruções ou acesso especiais a locais de memória com semântica particular. Seja como for, do ponto de vista de uma linguagem de progamação de alto-nível o uso desses recursos é complicado e específico para a arquitetura da máquina. C provê a nível de linguagem e independente da arquitetura do computador noções que correspondem diretamente a importantes conceitos de hardware: caracteres para usar bytes, inteiros para palavras, ponteiros para mecanismos de endereçamento, funções para abstração de programa e ausência de recursos rígidos de linguagem para que o programador possa manipular os detalhes complicados e inevitáveis específicos de hardware. O efeito dessas características é que C é relativamente fácil de aprender e usar em áreas onde conhecimento de hardware é importante. 'Vetores e ponteiros' Um vetor no C é simplesmente uma sequência de locais de memória. A notação [] é usada na declaração para informar o tamanho do vetor e em exepressões fazendo referência aos elementos do vetor. Exemplo: int v10; // um vetor de 10 inteiros v3 = 1; // atribui 1 a v3 int x = v3; // lê de v3 Um ponteiro é uma variável que armazena um endereço de memória. A notação * é usada na declaração para indicar um ponteiro e em expressões, onde significa o elemento para o qual o ponteiro aponta. int* p; // p é um ponteiro para inteiro p = &v7; //atribui o endereço de v7 para p *p = 4; // escrever para v7 através de p int y = *p; // ler de v7 através de p O C++ adotou essa noção, e também adotou a noção do C de expressões, estruturas de controle e funções. 'Armazenamento' No C++ existem basicamente 3 modos de usar a memória: *Memória estática, na qual um objeto é alocado e persiste até o final do programa, sem que seu endereço mude. Variáveis globais, membros estáticos de classes e variáveis estáticas em funções são alocados em memória estática. *Memória automática, no qual argumentos de funções e variáveis locais são alocados. Esse tipo de memória é criado e destruído automaticamente, como sugere o nome. Este tipo de memória é comumente chamado de stack (ou em português, pilha). *Memória dinâmica, da qual a memória para objetos é explicitamente solicitada pelo programa e um programa pode liberar a memória novamente (usando operadores new e delete). Quando programas precisam de espaço livre, o comando new solicita do sistema operacional. Tipicamente a memória dinâmica (também chamada de heap) aumenta com o tempo de vida do programa, já que a memória nunca é retornada ao sistema operacional para ser usada em outros programas. Exemplo: int g = 7; // variável local, alocada estaticamente void f() { int loc = 9; // variável local, alocada na stack int* p = new int; // variável alocada de forma dinâmica // ... delete p; // retorna variável apontada por p para possível reuso } Ao contrário de outras linguagens como JAVA, o C++ não possui um gerenciador de memória padrão, e cabe ao programador gerenciar a memória. Existem, no entanto, muitos garbage collectors de qualidade para C++, comerciais e gratuitos. 'Compilar, ligar e executar' Tradicionalmente, um programa C/C++ consiste em vários arquivos de código que são compilados individualmente e geram arquivos objeto. Depois disso são ligados e produzem um arquivo executável. Cada fragmento de programa compilado individualmente tem uma interface com o mínimo de informação necessária para ser usado. A interface é incluida (com #include) em cada unidade de tradução que a usa. Além disso, pode-se incluir a interface na unidade de tradução que a define para o compilador já diagnosticar inconsistências. O ligador confere se os nomes estão sendo usados de forma consistente em diferentes unidades de compilação e também confere se todo nome usado realmente se refere a algo que foi devidamente definido. Um típico ambiente de execução do C++ realiza alguns testes, mas cabe ao programador que quiser testes em tempo de execução prove-los como parte do código fonte. 'Checagem de tipos' A checagem de tipos do C++ é estática. Cada entidade no programa possui um tipo e precisa ser usado em concordância com o tipo ao qual pertence. Para tipos definidos pelo usuário, o usuário (programador) tem flexibilidade para definir quais operações e conversões são aceitáveis. Consequentemente, o compilador pode detectar inconsistências em tipos primitivos do C++ e em tipos definidos pelo usuário. Exemplo de código: void g() { int f(double) ; // f é uma função que pega um ponto flutuante de dupla precisão // e retorna um int float x = 2.0; // x é um ponto flutuante string s = "2"; // s é uma string de caracteres int i = f(x x) ; // i é um inteiro s = 7; // erro: não pode converter string para int x = "a a s string literal"; // erro: não pode converter string para float x = 7.0; // ok x = 7; // ok: converte int para float f(x) ; // ok: converte float para double f(i) ; // ok: converte int para double f(s) ; // erro: não pode converter string para double double e d = f+i; // ok: adiciona int para float string s s2 = s+i; // error: não pode adicionar int para string } Sintaxe 'Operadores' |} *Palavras Reservadas 'Legibilidade' 'Simplicidade' O C++ é uma linguagem de nível intermediário, ou seja tanto próxima da linguagem de máquina como próximo da linguagem do homem. A partir disto, percebe-se que o C++ não é uma linguagem de legibilidade simples. Ela possui identificadores livres, palavras reservadas mnemônicas e estruturas de controle básicas, uma boa estruturação do código com os separadores e isolamento de expressões, não é uma linguagem que sofre uma falta de estruturas como Hugs. Por outro lado, é uma linguagem de amplas possibilidades, assim como o C e o PHP, não limitando o programador, logo há diversas formas de se implementar uma solução mesmo que ela seja a errada, obrigando o programador a saber exatamente o que está fazendo, caso contrário, encontrará vários problemas. O próprio criador da linguagem alerta os programadores quanto a isto. O fato de também possuir muitos componentes básicos faz com que seja difícil a sua leitura, pois há diversas estruturas e tokens diferentes. Isso pode aumentar o leque de opções, porém pode fazer com que o programador se perca. Possui uma sobrecarga em alguns operadores como o “*” que pode ser tanto um operador aritmético como um indicador de ponteiro, podendo ser confuso em certo momentos. 'Ortogonalidade' 'Instruções de Controle' Nesse quesito C++ não tem uma boa performance, de forma que o código pode assumir qualquer rumo dependendo dos caminhos que cada subprograma toma. Um dos fatores que agrava esta propriedade é a estrutura de goto que faz o programa tomar caminhos inesperados. Além disso, o fator da modularização de códigos, dividindo-os em diferentes arquivos agrava este problema, de modo que pode haver uma referência de um subprograma em um arquivo porém sua instrução estar em outra parte. Logo, o programador terá dificuldades na hora de entender um programa inteiro. 'Estruturas e Tipos de Dados' A linguagem possui as estruturas comuns de controle derivadas do C, como o for, while, if, else, etc., porém ela ainda obtem o auxilio das estruturas provindas da orientação a objetos que são as classes e objetos. Estas dão uma maior legibilidade ao código, porém não são uma característica própria da linguagem. As structs também estão presentes no C++, porém aqui elas serão tratadas como tipos primitivos de dados, como as classes e podem conter funções. Ou seja, serão tratadas como tipos nativos A tipagem de dados no C++ é importante. Todas as variáveis devem ser previamente declaradas e, em decorrência da orientação a objetos, existem diversos tipos que cada variável, função, classe e método podem assumir. Isso permite que haja uma legibilidade melhor sobre o que cada instancia do programa esta fazendo e se pode ser acessada ou alterada. Comparado a outras linguagens, percebe-se que o C++ tem uma boa estruturação e tipagem de dados. Possui estruturas, diferentes de Hugs, Prolog, etc, que garantem um entendimento do que está ocorrendo no código. 'Sintaxe' C++ é uma linguagem com uma sintaxe complexa. Possui uma sintaxe muito igual à do C, porém com adicionais, principalmente no âmbito da programação orientada à objetos. As palavras reservadas são curtas e garantem um entendimento razoável ao passo que são explicativas e não podem ser usadas como variáveis, logo são únicas. Os identificadores são livres, permitindo o programador decidir livremente o nome de variáveis e sub-rotinas. Isso dá uma liberdade a mais, porém deve ser usada com atenção para o mesmo não comprometer a leitura do código. Com o paradigma da orientação a objetos é possível que sintaxe do C++ possa apresentar segmentos de códigos que sejam compreensíveis ao programador no quesito da ação efetiva deles, ou seja, o programador entende o código faz. Isso ocorre pois o programa está usando termos do problema para resolver o mesmo. Entretanto, ao usar outros paradigmas é possível que o código fique um pouco mais confuso. A gramática da linguagem é complexa. É difícil de escrever um bom analisador sintático para o código fonte da linguagem e existem muitas formas de ambiguidade dentro da linguagem, problemas que foram herdados do C. Nesse ponto, é exigido cuidado do programador. *'Inline Function: '''C++ possui algumas estruturas interessantes em sua sintaxe. Uma delas é a função inline. Estas são compiladas na sequencia do código, ou seja, ao invés de ser usada a chamada da função durante a compilação, é usado o código da mesma em si. Isso faz com que a execução seja mais ágil de modo que não é necessário ir para o bloco da função, executa-la e voltar para o subprograma de origem. *'Ponteiros: O C++ também herdou do C um interessante meio de controle de referências e endereçamento de variáveis ao longo da memória: os ponteiros. Estes são referências a endereço de memórias que podem conter valores de variáveis, sendo que estes também possuem uma verificação de tipo. Além de ser uma ferramenta inteligente e muito útil, ela foi melhorada e facilitada através de bibliotecas implementadas para a linguagem. Entretanto, demandam muito conhecimento por parte do programador. '''Capacidade de Escrita 'Confiabilidade' SLC CUZAO 'Verificação de Tipos e Tipagem' 'Tratamento de Erros' ''Aliasing 'Gabarito' Esta é uma propriedade do C++ é a que permite uso de diferentes tipos de dados em subprogramas sobrecarregados, que possuem uma implementação genérica, compatível com diversos tipos de dados, tornando-os universais no código. Esta implementação também está disponível para classes, de forma que cria-se um gabarito de classe que é um tipo parametrizado. Eles exigem um ou mais parâmetros para especificar como personalizar uma gabarito de classe genérica e formar esta classe especifica. template T maximo(T x,T y,T z){ T max = x; if(y > max) max = y; if(z > max) max = z; return max; } /* a função máximo poderá fazer a comparação do maior */ /* elemento, para qualquer tipo especificado por T*/ 'Custo0'''